"""
主题: 判断线程是否已经启动
问题: 你已经启动了一个线程，但是你想知道它是不是真的已经开始运行了
提示 : 
    event对象的一个重要特点是当它被设置为真时会唤醒所有等待它的线程。如果你只想唤醒单个线程，最好是使用信号量或者 Condition 对象来替代
"""

from threading import Thread, Event
import time
import threading

# Code to execute in an independent thread
def countdown(n, started_evt):
    '''使用Event对象'''
    print('countdown starting')
    started_evt.set()
    while n > 0:
        print('T-minus', n)
        n -= 1
        time.sleep(2)

class PeriodicTimer:
    '''如果一个线程需要不停地重复使用 event 对象，你最好使用 Condition 对象来代替'''
    def __init__(self, interval):
        self._interval = interval
        self._flag = 0
        self._cv = threading.Condition()

    def start(self):
        t = threading.Thread(target=self.run)
        t.daemon = True

        t.start()

    def run(self):
        '''
        Run the timer and notify waiting threads after each interval
        '''
        while True:
            time.sleep(self._interval)
            with self._cv:
                 self._flag ^= 1
                 self._cv.notify_all()

    def wait_for_tick(self):
        '''
        Wait for the next tick of the timer
        '''
        with self._cv:
            last_flag = self._flag
            while last_flag == self._flag:
                self._cv.wait()

# Worker thread
def worker(n, sema):
    '''信号量实现'''

    # Wait to be signaled
    sema.acquire()
    # Do some work
    print('Working', n)

def recipe1():
    # Create the event object that will be used to signal startup
    started_evt = Event()

    # Launch the thread and pass the startup event
    print('Launching countdown')
    t = Thread(target=countdown, args=(5,started_evt))
    t.start()

    # Wait for the thread to start
    started_evt.wait()
    print('countdown is running')

    t.join()

def recipe2():
    # Example use of the timer
    ptimer = PeriodicTimer(5)
    ptimer.start()

    # Two threads that synchronize on the timer
    def countdown(nticks):
        while nticks > 0:
            ptimer.wait_for_tick()
            print('T-minus', nticks)
            nticks -= 1

    def countup(last):
        n = 0
        while n < last:
            ptimer.wait_for_tick()
            print('Counting', n)
            n += 1

    t1 = threading.Thread(target=countdown, args=(10,))
    t2 = threading.Thread(target=countup, args=(5,))
    t1.start()
    t2.start()

    t1.join()
    t2.join()

def recipe3():
    # Create some threads
    sema = threading.Semaphore(0)
    nworkers = 10
    for n in range(nworkers):
        t = threading.Thread(target=worker, args=(n, sema,))
        t.start()
    
    time.sleep(2)
    for n in range(nworkers):
        sema.release()
        time.sleep(1)
    

def main():
    print('recipe1'.center(20, '*'))
    recipe1()
    print('recipe2'.center(20, '*'))
    recipe2()
    print('recipe3'.center(20, '*'))
    recipe3()

if __name__ == '__main__':
    main()          